PHUSE US Connect 2024
Population Pharmacokinetic modeling is an important tool for drug development. The CDISC ADaM Population PK Implementation Guide is forthcoming. Population PK models generally make use of nonlinear mixed effects models that require numeric variables. The data used in the models will include both dosing and concentration records, relative time variables, and numeric covariate variables. {admiral} is an open-source R package for creating CDISC ADaM data. It can be used effectively to create Population PK analysis data (ADPPK). Additional tools from other Pharmaverse packages such as {metacore}, {metatools} and {xportr} can be used to simplify the workflow. I will discuss some of the challenges of Population Pharmacokinetic analysis data programming and show some of the solutions developed in {admiral} and the Pharmaverse.
{admiral} and the PharmaversePharmacokinetics is the interaction of a drug with the body
Samples collected at regular time intervals after dosing
Metrics calculated from concentrations over time
Non-Compartmental Analysis (NCA)
Population PK (PopPK)
ADPPKPublished October 6, 2023!
ADNCA (NCA) – released November 2021ADPPK (PopPK) – released October 2023ADPP (PK Parameters) – coming in 2024EX) and concentration data (PC)ADNCA)ADPPK)ADPPK)| Variable | Variable Label |
|---|---|
NFRLT |
Nominal Rel Time from First Dose |
AFRLT |
Actual Rel Time from First Dose |
NPRLT |
Nominal Rel Time from Previous Dose |
APRLT |
Actual Rel Time from Previous Dose |
USUBJID |
EVID |
NFRLT |
AFRLT |
NPRLT |
ARRLT |
|---|---|---|---|---|---|
| 001 | 0 | 0 | -0.05 | 0 | -0.05 |
| 001 | 1 | 0 | 0 | 0 | 0 |
| 001 | 0 | 0.5 | 0.465 | 0.5 | 0.465 |
| 001 | 0 | 3 | 2.89 | 3 | 2.89 |
| 001 | 1 | 24 | 24.05 | 0 | 0 |
| 001 | 0 | 25 | 25.15 | 1 | 1.15 |
ADPPK Expected VariablesEVID Event IDDV Dependent VariableMDV Missing Dependent VariableBLQ Below Limit of QuantitationADPPK Covariates<COV>BL for baseline covariate, (e.g., WTBL, BMIBL)<COV>N for numerical version of categorical covariate (e.g., SEXN, RACEN)<COV>I for any covariates with imputed values (e.g., WTI, BMII)<COV>GRy for grouping covariates (e.g. AGEGR1){admiral}ADaM in R Asset Library{admiral} is Open Source and Collaborative{admiral} is Modular{admiral} is Part of Pharmaverse{admiral} Functions Usedderive_vars_dtm()derive_vars_dtm_to_dt()derive_vars_dtm_to_tm()derive_vars_dy()derive_vars_duration()create_single_dose_dataset(){admiral} Functions Used (continued)derive_vars_merged()derive_vars_joined()derive_vars_transposed()compute_bmi()compute_bsa()compute_egfr()ADPPK Workflow{pharmaversesdtm} CDISC pilot SDTM data{metacore} Store metadata{metatools} Work with metadata and perform checks{xportr} Perform checks and export transport files (XPT)https://pharmaverse.github.io/e2e_pk/
Will focus on ADPPK example
{metacore}{metacore}{metacore} Checks{xportr} Steps{metacore}pc_dates <- pc %>%
# Join ADSL with PC (need TRTSDT for ADY derivation)
derive_vars_merged(
dataset_add = adsl,
new_vars = adsl_vars,
by_vars = exprs(STUDYID, USUBJID)
) %>%
# Derive analysis date/time
# Impute missing time to 00:00:00
derive_vars_dtm(
new_vars_prefix = "A",
dtc = PCDTC,
time_imputation = "00:00:00"
) %>%
# Derive dates and times from date/times
derive_vars_dtm_to_dt(exprs(ADTM)) %>%
derive_vars_dtm_to_tm(exprs(ADTM)) %>%
# Derive event ID and nominal relative time from first dose (NFRLT)
mutate(
EVID = 0,
DRUG = PCTEST,
NFRLT = if_else(PCTPTNUM < 0, 0, PCTPTNUM), .after = USUBJID
)ex_exp <- ex_dates %>%
create_single_dose_dataset(
dose_freq = EXDOSFRQ,
start_date = ASTDT,
start_datetime = ASTDTM,
end_date = AENDT,
end_datetime = AENDTM,
nominal_time = NFRLT,
lookup_table = dose_freq_lookup,
lookup_column = CDISC_VALUE,
keep_source_vars = exprs(
STUDYID, USUBJID, EVID, EXDOSFRQ, EXDOSFRM,
NFRLT, EXDOSE, EXDOSU, EXTRT, ASTDT, ASTDTM, AENDT, AENDTM,
VISIT, VISITNUM, VISITDY,
TRT01A, TRT01P, DOMAIN, EXSEQ, !!!adsl_vars
)
) %>%
# Derive AVISIT based on nominal relative time
# Derive AVISITN to nominal time in whole days using integer division
# Define AVISIT based on nominal day
mutate(
AVISITN = NFRLT %/% 24 + 1,
AVISIT = paste("Day", AVISITN),
ADTM = ASTDTM,
DRUG = EXTRT
) %>%
# Derive dates and times from datetimes
derive_vars_dtm_to_dt(exprs(ADTM)) %>%
derive_vars_dtm_to_tm(exprs(ADTM)) %>%
derive_vars_dtm_to_tm(exprs(ASTDTM)) %>%
derive_vars_dtm_to_tm(exprs(AENDTM))adppk_first_dose <- pc_dates %>%
derive_vars_merged(
dataset_add = ex_exp,
filter_add = (!is.na(ADTM)),
new_vars = exprs(FANLDTM = ADTM, EXDOSE_first = EXDOSE),
order = exprs(ADTM, EXSEQ),
mode = "first",
by_vars = exprs(STUDYID, USUBJID, DRUG)
) %>%
filter(!is.na(FANLDTM)) %>%
# Derive AVISIT based on nominal relative time
# Derive AVISITN to nominal time in whole days using integer division
# Define AVISIT based on nominal day
mutate(
AVISITN = NFRLT %/% 24 + 1,
AVISIT = paste("Day", AVISITN),
)adppk_prev <- adppk_first_dose %>%
derive_vars_joined(
dataset_add = ex_exp,
by_vars = exprs(USUBJID),
order = exprs(ADTM),
new_vars = exprs(
ADTM_prev = ADTM, EXDOSE_prev = EXDOSE, AVISIT_prev = AVISIT,
AENDTM_prev = AENDTM
),
join_vars = exprs(ADTM),
join_type = "all",
filter_add = NULL,
filter_join = ADTM > ADTM.join,
mode = "last",
check_type = "none"
)Use metatools::create_var_from_codelist()
#---- Derive Covariates ----
covar <- adsl %>%
create_var_from_codelist(metacore, input_var = STUDYID, out_var = STUDYIDN) %>%
create_var_from_codelist(metacore, input_var = SEX, out_var = SEXN) %>%
create_var_from_codelist(metacore, input_var = RACE, out_var = RACEN) %>%
create_var_from_codelist(metacore, input_var = ETHNIC, out_var = AETHNIC) %>%
create_var_from_codelist(metacore, input_var = AETHNIC, out_var = AETHNICN) %>%
create_var_from_codelist(metacore, input_var = ARMCD, out_var = COHORT) %>%
create_var_from_codelist(metacore, input_var = ARMCD, out_var = COHORTC) %>%
create_var_from_codelist(metacore, input_var = COUNTRY, out_var = COUNTRYN) %>%
create_var_from_codelist(metacore, input_var = COUNTRY, out_var = COUNTRYL) %>%
mutate(
STUDYIDN = as.numeric(word(USUBJID, 1, sep = fixed("-"))),
SITEIDN = as.numeric(word(USUBJID, 2, sep = fixed("-"))),
USUBJIDN = as.numeric(word(USUBJID, 3, sep = fixed("-"))),
SUBJIDN = as.numeric(SUBJID),
ROUTE = unique(ex$EXROUTE),
FORM = unique(ex$EXDOSFRM),
REGION1 = COUNTRY,
REGION1N = COUNTRYN,
SUBJTYPC = "Volunteer",
) %>%
create_var_from_codelist(metacore, input_var = FORM, out_var = FORMN) %>%
create_var_from_codelist(metacore, input_var = ROUTE, out_var = ROUTEN) %>%
create_var_from_codelist(metacore, input_var = SUBJTYPC, out_var = SUBJTYP)covar_vslb <- covar %>%
derive_vars_merged(
dataset_add = vs,
filter_add = VSTESTCD == "HEIGHT",
by_vars = exprs(STUDYID, USUBJID),
new_vars = exprs(HTBL = VSSTRESN)
) %>%
derive_vars_merged(
dataset_add = vs,
filter_add = VSTESTCD == "WEIGHT" & VSBLFL == "Y",
by_vars = exprs(STUDYID, USUBJID),
new_vars = exprs(WTBL = VSSTRESN)
) %>%
derive_vars_transposed(
dataset_merge = labsbl,
by_vars = exprs(STUDYID, USUBJID),
key_var = LBTESTCDB,
value_var = LBSTRESN
) %>%
mutate(
BMIBL = compute_bmi(height = HTBL, weight = WTBL),
BSABL = compute_bsa(
height = HTBL,
weight = HTBL,
method = "Mosteller"
),
CRCLBL = compute_egfr(
creat = CREATBL, creatu = "SI", age = AGE, weight = WTBL, sex = SEX,
method = "CRCL"
),
EGFRBL = compute_egfr(
creat = CREATBL, creatu = "SI", age = AGE, weight = WTBL, sex = SEX,
method = "CKD-EPI"
)
) %>%
rename(TBILBL = BILIBL){metacore} Checksadppk <- adppk_prefinal %>%
drop_unspec_vars(metacore) %>% # Drop unspecified variables from specs
check_variables(metacore) %>% # Check all variables specified are present and no more
check_ct_data(metacore) %>% # Checks all variables with CT only contain values within the CT
order_cols(metacore) %>% # Orders the columns according to the spec
sort_by_key(metacore) # Sorts the rows by the sort keys{xportr} Stepsadppk_xpt <- adppk %>%
xportr_type(metacore) %>% # Coerce variable type to match spec
xportr_length(metacore) %>% # Assigns SAS length from a variable level metadata
xportr_label(metacore) %>% # Assigns variable label from metacore specifications
xportr_format(metacore) %>% # Assigns variable format from metacore specifications
xportr_df_label(metacore) %>% # Assigns dataset label from metacore specifications
xportr_write(file.path(dir, "adppk.xpt")) # Write xpt v5 transport fileADPPK_XPT USUBJID EVID NFRLT NPRLT AFRLT APRLT DV
1 01-701-1028 0 0.00 0.00 -0.50000000 -0.50000000 0.00000000
2 01-701-1028 1 0.00 0.00 0.00000000 0.00000000 NA
3 01-701-1028 0 0.08 0.08 0.08333333 0.08333333 0.10156622
4 01-701-1028 0 0.50 0.50 0.50000000 0.50000000 0.54690177
5 01-701-1028 0 1.00 1.00 1.00000000 1.00000000 0.92546539
6 01-701-1028 0 1.50 1.50 1.50000000 1.50000000 1.18750588
7 01-701-1028 0 2.00 2.00 2.00000000 2.00000000 1.36888945
8 01-701-1028 0 4.00 4.00 4.00000000 4.00000000 1.68314758
9 01-701-1028 0 6.00 6.00 6.00000000 6.00000000 1.75529232
10 01-701-1028 0 8.00 8.00 8.00000000 8.00000000 1.77185470
11 01-701-1028 0 12.00 12.00 12.00000000 12.00000000 0.49503585
12 01-701-1028 0 16.00 16.00 16.00000000 16.00000000 0.13792316
13 01-701-1028 0 24.00 24.00 24.00000000 24.00000000 0.01070627
14 01-701-1028 1 24.00 0.00 24.00000000 0.00000000 NA
15 01-701-1028 0 36.00 12.00 36.00000000 12.00000000 NA
16 01-701-1028 0 48.00 24.00 48.00000000 24.00000000 NA
17 01-701-1028 1 48.00 0.00 48.00000000 0.00000000 NA
18 01-701-1033 0 0.00 0.00 -0.50000000 -0.50000000 0.00000000
19 01-701-1033 1 0.00 0.00 0.00000000 0.00000000 NA
20 01-701-1033 0 0.08 0.08 0.08333333 0.08333333 0.10052550
ADNCA and ADPPK available{admiral} template programs exist for these{admiral} Core Team